package myicesscheduler.web;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import myicesscheduler.hibernate.HibernateUtilPublic;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.SimpleFormController;

public class AdminBackupRestoreController extends SimpleFormController
{
   protected final Log logger = LogFactory.getLog( getClass() );

   public ModelAndView handleRequest( HttpServletRequest request, HttpServletResponse response )
         throws Exception
   {
      if( false == LoginController.isAdmin( request ) ) return LectureListController.redirect();

      return AdminMenuController.redirect_toAnchor( "LastRestoredDate" );
   }

   @Override
   protected ModelAndView onSubmit( Object command ) throws Exception
   {
      if( null == command ) logger.info( "onSubmit: command object is null" );
      final AdminMenuCommand cmd = (AdminMenuCommand) command;
      logger.info( "onSubmit: " + cmd.toString() );

      final Method[] methods = AdminMenuCommand.class.getMethods();
      for( final Method method : methods )
      {
         final String methodName = method.getName();
         if( false == methodName.startsWith( AdminMenuCommand.methodNameOfUploadBackups ) )
            continue;

         final MultipartFile uploadFile = (MultipartFile) method.invoke( cmd, new Object[] {} );
         if( null == uploadFile ) continue;
         if( null == uploadFile.getName() || "".equals( uploadFile.getName() ) ) continue;
         logger.info( "Storing UPLOAD file: " + uploadFile.getName() );

         final String storedFilename = MyFileUtil
               .storeFile( uploadFile, MyFolderUtil.restoreFolder );
         logger.info( "Stored UPLOAD filename: " + storedFilename );
      }

      //return super.onSubmit( command );
      return AdminMenuController.redirect_toAnchor( "LastRestoredDate" );
   }

   public void decompressFile( String zipFilename )
   {
      logger.info( "Decompress file: " + zipFilename );
      final FileInputStream fis = getFileInputStream( zipFilename );
      final ZipInputStream zin = new ZipInputStream( new BufferedInputStream( fis ) );

      for( ZipEntry entry = getNextEntry( zin ); entry != null; entry = getNextEntry( zin ) )
      {
         final String entryName = entry.getName();
         logger.info( "Decompress entry: " + entryName );

         byte[] data = getEntryData( zin );
         storeFile( entryName, data );
      }
   }

   private byte[] getEntryData( final ZipInputStream zin )
   {
      byte[] data = new byte[ 0 ];
      byte[] buffer = new byte[ 512 * 4 ];

      try
      {
         int count = 0;
         while( ( count = zin.read( buffer, 0, buffer.length ) ) != -1 )
         {
            final int prevDataSize = data.length;

            byte[] tmpData = new byte[ prevDataSize + count ];
            System.arraycopy( data, 0, tmpData, 0, prevDataSize );
            data = tmpData;

            System.arraycopy( buffer, 0, data, prevDataSize, count );
         }
      } catch( IOException e )
      {
         e.printStackTrace();
         throw new RuntimeException( "Entry from a compressed file cannot be read." );
      }
      return data;
   }

   private ZipEntry getNextEntry( final ZipInputStream zin )
   {
      ZipEntry entry = null;
      try
      {
         entry = zin.getNextEntry();
      } catch( IOException e )
      {
         e.printStackTrace();
         throw new RuntimeException( "Compress file includes currupted entry." );
      }
      return entry;
   }

   private FileInputStream getFileInputStream( String zipFilename )
   {
      FileInputStream fis = null;
      try
      {
         fis = new FileInputStream( zipFilename );
      } catch( FileNotFoundException e )
      {
         e.printStackTrace();
         throw new RuntimeException( "Compressed file not found: " + zipFilename );
      }
      return fis;
   }

   private void storeFile( final String filename, byte[] data )
   {
      final String fullpath_LowerCase = filename.toLowerCase();
      final String databaseFilename = HibernateUtilPublic.getDatabaseName().toLowerCase() + ".";

      final String[] delims = new String[] { String.valueOf( File.separatorChar ), "/", "\\" };
      for( final String delim : delims )
      {
         final int endofFolder = fullpath_LowerCase.lastIndexOf( delim );
         final int beginofDB = fullpath_LowerCase.lastIndexOf( databaseFilename, endofFolder );
         final boolean bDB = beginofDB >= 0;
         if( false == bDB ) continue;

         logger.info( "Overwritting Database backup files." );
         MyFolderUtil.databaseFolder.storeFile( filename, data );
         return;
      }

      logger.info( "Storing download files." );
      MyFolderUtil.uploadFolder.storeFile( filename, data );
   }
}
